const natural = require('natural');
const compromise = require('compromise');
const Card = require('../models/Card');
const AiModelService = require('./aiModelService');

/**
 * 知识卡片生成服务
 * 负责将文档内容切分为知识卡片
 */
class CardGenerator {
  /**
   * 从文档内容生成知识卡片
   * @param {string} content - 文档内容
   * @param {Array} structure - 文档结构
   * @param {string} documentId - 文档ID
   * @param {Object} progress - 处理进度对象
   * @returns {Promise<Array>} - 生成的知识卡片数组
   */
  static async generateCards(content, structure, documentId, progress = {}) {
    try {
      console.log(`[CardGenerator] 开始为文档 ${documentId} 生成卡片`);
      
      const cards = [];
      
      // 获取已保存的处理进度
      const processedChunks = progress.processedChunks || 0;
      const currentChapter = progress.currentChapter || 0;
      let totalChunks = progress.totalChunks || 0;
      
      // 如果有章节结构，按章节处理
      if (structure && structure.length > 0) {
        // 计算总块数（如果是第一次处理）
        if (totalChunks === 0) {
          for (const chapter of structure) {
            const chapterContent = content.substring(chapter.startIndex, chapter.endIndex);
            if (chapterContent && chapterContent.trim().length >= 50) {
              const chunks = this.splitContentForAI(chapterContent);
              totalChunks += chunks.length;
            }
          }
          
          // 更新文档的处理进度
          await this.updateProcessingProgress(documentId, {
            processedChunks: 0,
            totalChunks,
            currentChapter: 0
          });
        }
        
        // 从上次处理的章节开始
        for (let i = currentChapter; i < structure.length; i++) {
          const chapter = structure[i];
          const chapterContent = content.substring(chapter.startIndex, chapter.endIndex);
          
          // 检查章节内容是否为空或太短
          if (!chapterContent || chapterContent.trim().length < 50) {
            console.warn(`章节 "${chapter.title}" 内容太短，跳过`);
            continue;
          }
          
          console.log(`处理章节: ${chapter.title} (长度: ${chapterContent.length})`);
          
          // 使用 AI 模型生成卡片，支持断点续传
          const chapterCards = await this.processChapterContentWithAI(
            chapterContent, 
            chapter.title, 
            documentId, 
            i === currentChapter ? processedChunks : 0
          );
          
          // 如果 AI 模型失败，使用传统方法
          if (!chapterCards || chapterCards.length === 0) {
            console.warn(`使用 AI 模型处理章节 "${chapter.title}" 失败，使用传统方法`);
            const fallbackCards = await this.processChapterContent(chapterContent, chapter.title, documentId);
            cards.push(...fallbackCards);
          } else {
            cards.push(...chapterCards);
          }
          
          // 更新处理进度
          await this.updateProcessingProgress(documentId, {
            processedChunks: 0, // 重置当前章节的处理块数
            totalChunks,
            currentChapter: i + 1
          });
        }
      } else {
        // 没有章节结构，直接处理整个内容
        const defaultChapter = "未分类内容";
        console.log(`处理未分类内容 (长度: ${content.length})`);
        
        // 计算总块数（如果是第一次处理）
        if (totalChunks === 0) {
          const chunks = this.splitContentForAI(content);
          totalChunks = chunks.length;
          
          // 更新文档的处理进度
          await this.updateProcessingProgress(documentId, {
            processedChunks: 0,
            totalChunks,
            currentChapter: 0
          });
        }
        
        // 使用 AI 模型生成卡片，支持断点续传
        const defaultCards = await this.processChapterContentWithAI(
          content, 
          defaultChapter, 
          documentId, 
          processedChunks
        );
        
        // 如果 AI 模型失败，使用传统方法
        if (!defaultCards || defaultCards.length === 0) {
          console.warn(`使用 AI 模型处理未分类内容失败，使用传统方法`);
          const fallbackCards = await this.processChapterContent(content, defaultChapter, documentId);
          cards.push(...fallbackCards);
        } else {
          cards.push(...defaultCards);
        }
        
        // 更新处理进度
        await this.updateProcessingProgress(documentId, {
          processedChunks: totalChunks,
          totalChunks,
          currentChapter: 0
        });
      }
      
      // 构建卡片之间的关联关系
      await this.buildCardRelationships(cards);
      
      console.log(`[CardGenerator] 卡片生成完成，准备保存到数据库`);
      
      // 保存卡片到数据库
      const savedCards = [];
      for (const card of cards) {
        try {
          const savedCard = await card.save();
          savedCards.push(savedCard);
        } catch (err) {
          console.error(`[CardGenerator] 保存卡片失败:`, err);
        }
      }
      
      console.log(`[CardGenerator] 成功保存了 ${savedCards.length} 张卡片到数据库`);
      
      return savedCards;
    } catch (error) {
      console.error(`[CardGenerator] 生成卡片时出错:`, error);
      throw error;
    }
  }

  /**
   * 使用通义千问 Qwen-Long 模型处理章节内容，生成知识卡片
   * @param {string} content - 章节内容
   * @param {string} chapterTitle - 章节标题
   * @param {string} documentId - 文档ID
   * @param {number} processedChunks - 已处理的块数
   * @returns {Promise<Array>} - 生成的知识卡片数组
   */
  static async processChapterContentWithAI(content, chapterTitle, documentId, processedChunks = 0) {
    const cards = [];
    
    try {
      console.log(`使用通义千问 Qwen-Long 模型处理章节: ${chapterTitle}`);
      
      // 如果内容过长，需要分块处理 - 减小块大小以提高处理成功率
      const contentChunks = this.splitContentForAI(content);
      console.log(`章节内容被分为 ${contentChunks.length} 个块进行处理`);
      
      // 从指定的块开始处理
      for (let i = processedChunks; i < contentChunks.length; i++) {
        const chunk = contentChunks[i];
        console.log(`处理块 ${i+1}/${contentChunks.length} (长度: ${chunk.length})`);
        
        // 尝试最多3次
        let attempts = 0;
        let success = false;
        let chunkCards = [];
        
        // 使用更明确的提示词，避免HTML响应
        const customPrompt = `请分析以下内容，生成高质量的知识卡片。每个卡片必须是一个完整的、自包含的知识点，便于学习者轻松理解和记忆。

要求：
1. 每个卡片必须包含一个完整的小知识点，而不是简单的文本片段
2. 卡片内容应该是自包含的，即使脱离原文也能独立理解
3. 卡片应该简洁明了，但必须包含足够的上下文和解释
4. 卡片难度应该适中，避免让学习者产生畏惧感
5. 适当添加例子或应用场景，帮助理解
6. 如果是技术内容，可以包含简短的代码示例

必须返回有效的JSON格式数组，每个卡片包含以下字段：
- title: 简洁明了的标题，清晰表达知识点主题
- content: 完整、自包含的知识点内容，包括必要的解释、例子和上下文
- tags: 相关的关键词标签，便于归类和检索
- difficulty: 难度级别，可选值为"EASY"、"MEDIUM"、"HARD"

示例输出格式：
[
  {
    "title": "变量作用域的基本概念",
    "content": "变量作用域是指变量在程序中可被访问的范围。在JavaScript中，主要有两种作用域：全局作用域和局部作用域。全局作用域中声明的变量可以在整个程序中访问，而局部作用域中声明的变量只能在特定函数或代码块中访问。理解作用域对于避免变量命名冲突和内存泄漏非常重要。例如：\\nlet globalVar = 'I am global';  // 全局变量\\nfunction myFunction() {\\n  let localVar = 'I am local';  // 局部变量\\n  console.log(globalVar);  // 可以访问\\n  console.log(localVar);  // 可以访问\\n}\\nconsole.log(globalVar);  // 可以访问\\nconsole.log(localVar);  // 错误：localVar未定义",
    "tags": ["JavaScript", "变量", "作用域", "编程基础"],
    "difficulty": "EASY"
  },
  {
    "title": "闭包的概念与应用",
    "content": "闭包是指一个函数能够访问并操作其词法作用域外部的变量的特性。当函数被定义时，它会记住创建时的环境。闭包常用于数据封装、创建私有变量和工厂函数。例如：\\nfunction createCounter() {\\n  let count = 0;  // 私有变量\\n  return function() {\\n    return ++count;  // 访问外部函数的变量\\n  };\\n}\\nconst counter = createCounter();\\nconsole.log(counter());  // 输出: 1\\nconsole.log(counter());  // 输出: 2\\n\\n这个例子中，返回的函数形成了一个闭包，可以访问并修改外部函数的count变量，而这个变量对外部是不可见的。",
    "tags": ["JavaScript", "闭包", "函数", "高级概念"],
    "difficulty": "MEDIUM"
  }
]

请注意：只返回纯文本JSON，不要返回HTML或Markdown格式。每个卡片的内容应该是完整的知识点，而不是简单的文本片段。`;
        
        while (attempts < 3 && !success) {
          try {
            // 调用通义千问 Qwen-Long 模型
            const response = await AiModelService.parseWithQwenLong(chunk, {
              task: 'generate_cards',
              temperature: 0.3,
              max_tokens: 1000,
              customPrompt: customPrompt
            });
            
            if (response.success) {
              const responseText = response.result;
              console.log(`AI返回原始文本 (块 ${i+1})，前100字符: ${responseText.substring(0, 100)}...`);
              
              // 检查是否为HTML格式
              if (responseText.includes('<html') || responseText.includes('<!DOCTYPE') || responseText.includes('<body')) {
                console.log('检测到HTML格式的响应，尝试提取纯文本...');
                const plainText = responseText.replace(/<[^>]*>/g, '');
                
                // 尝试从HTML中提取JSON
                const jsonMatch = plainText.match(/\[\s*\{[\s\S]*\}\s*\]/);
                if (jsonMatch) {
                  console.log('从HTML中提取到JSON格式数据');
                  try {
                    chunkCards = JSON.parse(jsonMatch[0]);
                    success = true;
                  } catch (jsonError) {
                    console.error('从HTML提取的JSON解析失败:', jsonError.message);
                    attempts++;
                    continue;
                  }
                } else {
                  console.log('无法从HTML中提取JSON，尝试下一次');
                  attempts++;
                  continue;
                }
              } else {
                // 处理代码块格式的响应
                if (responseText.includes('```json') || responseText.includes('```')) {
                  console.log('检测到代码块格式的响应，尝试提取JSON...');
                  
                  // 提取代码块中的JSON
                  const codeBlockMatch = responseText.match(/```(?:json)?\s*([\s\S]*?)```/);
                  if (codeBlockMatch && codeBlockMatch[1]) {
                    try {
                      chunkCards = JSON.parse(codeBlockMatch[1]);
                      success = true;
                    } catch (jsonError) {
                      console.error('从代码块提取的JSON解析失败:', jsonError.message);
                      // 尝试清理可能的格式问题
                      try {
                        const cleanedJson = codeBlockMatch[1]
                          .replace(/,\s*]/g, ']') // 移除数组末尾多余的逗号
                          .replace(/,\s*}/g, '}') // 移除对象末尾多余的逗号
                          .trim();
                        chunkCards = JSON.parse(cleanedJson);
                        success = true;
                      } catch (cleanError) {
                        console.error('清理后的JSON仍然解析失败:', cleanError.message);
                        attempts++;
                        continue;
                      }
                    }
                  } else {
                    console.log('无法从代码块中提取JSON，尝试直接解析');
                    try {
                      chunkCards = JSON.parse(responseText);
                      console.log('成功直接解析JSON');
                      success = true;
                    } catch (directError) {
                      console.error('直接解析JSON失败:', directError.message);
                      attempts++;
                      continue;
                    }
                  }
                } else {
                  // 尝试直接解析JSON
                  try {
                    chunkCards = JSON.parse(responseText);
                    console.log('成功直接解析JSON');
                    success = true;
                  } catch (jsonError) {
                    console.error('直接解析JSON失败:', jsonError.message);
                    attempts++;
                    continue;
                  }
                }
              }
              
              // 如果成功解析，处理卡片
              if (success && Array.isArray(chunkCards)) {
                console.log(`AI 模型为块 ${i+1} 生成了 ${chunkCards.length} 张卡片`);
                
                // 为每个卡片添加元数据
                for (const cardData of chunkCards) {
                  try {
                    // 转换难度值为数字
                    const difficulty = this.convertDifficultyToNumber(cardData.difficulty);
                    
                    // 创建卡片模型
                    const Card = require('../models/Card');
                    const card = new Card({
                      title: cardData.title,
                      content: cardData.content,
                      tags: cardData.tags || [],
                      sourceDocument: documentId,
                      chapter: chapterTitle,
                      difficulty: difficulty,
                      order: cards.length + 1  // 设置卡片顺序
                    });
                    
                    cards.push(card);
                  } catch (cardError) {
                    console.error(`保存卡片关系时出错 (卡片ID: ${cardData._id}):`, cardError);
                  }
                }
              }
            } else {
              console.error(`API 调用失败:`, response.error);
              attempts++;
            }
          } catch (error) {
            console.error(`处理块 ${i+1} 时出错:`, error);
            attempts++;
          }
        }
        
        // 更新处理进度
        await this.updateProcessingProgress(documentId, {
          processedChunks: i + 1,
          totalChunks: contentChunks.length,
          currentChapter: 0  // 当前章节索引由外部函数管理
        });
        
        // 如果所有尝试都失败，记录错误
        if (!success) {
          console.error(`无法处理块 ${i+1}/${contentChunks.length}，跳过`);
        }
      }
      
      return cards;
    } catch (error) {
      console.error(`处理章节 "${chapterTitle}" 时出错:`, error);
      return [];
    }
  }

  /**
   * 将长内容分割为适合 AI 处理的块
   * @param {string} content - 内容
   * @returns {Array<string>} - 内容块数组
   */
  static splitContentForAI(content) {
    // 减小每块最大字符数，提高处理成功率
    const MAX_CHUNK_LENGTH = 2000; // 减小每块最大字符数
    const chunks = [];
    
    // 如果内容不超过最大长度，直接返回完整内容
    if (content.length <= MAX_CHUNK_LENGTH) {
      chunks.push(content);
      return chunks;
    }
    
    // 优先按章节或自然段落分割
    const sections = content.split(/(?:^|\n)(?=第[一二三四五六七八九十百千万]+[章节]|Chapter\s+\d+|\d+\.\s+[^\n]+|\d+\.\d+\s+[^\n]+)/);
    
    let currentChunk = '';
    
    // 处理每个章节
    for (const section of sections) {
      const trimmedSection = section.trim();
      if (!trimmedSection) continue;
      
      // 如果当前章节加上当前块会超出最大长度，先保存当前块
      if (currentChunk.length + trimmedSection.length > MAX_CHUNK_LENGTH) {
        if (currentChunk) {
          chunks.push(currentChunk);
        }
        
        // 如果单个章节超过最大长度，需要进一步分割
        if (trimmedSection.length > MAX_CHUNK_LENGTH) {
          // 按段落分割
          const paragraphs = trimmedSection.split(/\n\s*\n/);
          let paragraphChunk = '';
          
          for (const paragraph of paragraphs) {
            const trimmedParagraph = paragraph.trim();
            if (!trimmedParagraph) continue;
            
            if (paragraphChunk.length + trimmedParagraph.length > MAX_CHUNK_LENGTH) {
              if (paragraphChunk) {
                chunks.push(paragraphChunk);
              }
              
              // 如果单个段落超过最大长度，按句子分割
              if (trimmedParagraph.length > MAX_CHUNK_LENGTH) {
                const sentences = trimmedParagraph.match(/[^.!?]+[.!?]+/g) || [trimmedParagraph];
                let sentenceChunk = '';
                
                for (const sentence of sentences) {
                  if (sentenceChunk.length + sentence.length > MAX_CHUNK_LENGTH) {
                    if (sentenceChunk) {
                      chunks.push(sentenceChunk);
                    }
                    sentenceChunk = sentence;
                  } else {
                    sentenceChunk += sentence;
                  }
                }
                
                if (sentenceChunk) {
                  chunks.push(sentenceChunk);
                }
              } else {
                paragraphChunk = trimmedParagraph;
              }
            } else {
              paragraphChunk += (paragraphChunk ? '\n\n' : '') + trimmedParagraph;
            }
          }
          
          if (paragraphChunk) {
            chunks.push(paragraphChunk);
          }
        } else {
          // 开始新块
          currentChunk = trimmedSection;
        }
      } else {
        // 添加到当前块
        currentChunk += (currentChunk ? '\n\n' : '') + trimmedSection;
      }
    }
    
    // 添加最后一个块
    if (currentChunk) {
      chunks.push(currentChunk);
    }
    
    console.log(`内容已分割为 ${chunks.length} 个块，平均长度: ${Math.round(content.length / chunks.length)} 字符`);
    
    return chunks;
  }

  /**
   * 处理章节内容，生成知识卡片（传统方法）
   * @param {string} content - 章节内容
   * @param {string} chapterTitle - 章节标题
   * @param {string} documentId - 文档ID
   * @returns {Promise<Array>} - 生成的知识卡片数组
   */
  static async processChapterContent(content, chapterTitle, documentId) {
    const cards = [];
    
    // 使用自然语言处理工具分割内容
    const segments = this.segmentContent(content);
    
    for (const segment of segments) {
      // 确保每个片段不超过500字
      const chunks = this.chunkText(segment, 500);
      
      for (const chunk of chunks) {
        // 提取关键词和标题
        const keywords = this.extractKeywords(chunk);
        const title = this.generateTitle(chunk, chapterTitle);
        
        // 分析内容难度
        const difficulty = this.analyzeDifficulty(chunk);
        
        // 创建卡片对象
        const card = new Card({
          title,
          content: chunk,
          chapter: chapterTitle,
          difficulty,
          tags: keywords,
          sourceDocument: documentId
        });
        
        // 保存卡片
        await card.save();
        cards.push(card);
      }
    }
    
    return cards;
  }

  /**
   * 将内容分割为有意义的片段
   * @param {string} content - 内容
   * @returns {Array<string>} - 内容片段数组
   */
  static segmentContent(content) {
    // 使用自然段落作为基本分割单位
    const paragraphs = content.split(/\n\s*\n/);
    
    // 进一步处理段落，合并短段落
    const segments = [];
    let currentSegment = '';
    
    for (const paragraph of paragraphs) {
      const trimmedParagraph = paragraph.trim();
      if (!trimmedParagraph) continue;
      
      // 如果当前段落很短，并且当前片段加上这个段落不会太长，则合并
      if (trimmedParagraph.length < 100 && currentSegment.length + trimmedParagraph.length < 400) {
        currentSegment += (currentSegment ? '\n\n' : '') + trimmedParagraph;
      } else {
        // 如果当前片段不为空，添加到结果中
        if (currentSegment) {
          segments.push(currentSegment);
        }
        
        // 开始新片段
        currentSegment = trimmedParagraph;
      }
    }
    
    // 添加最后一个片段
    if (currentSegment) {
      segments.push(currentSegment);
    }
    
    return segments;
  }

  /**
   * 将文本分块，确保每块不超过指定字数
   * @param {string} text - 文本
   * @param {number} maxLength - 最大字数
   * @returns {Array<string>} - 文本块数组
   */
  static chunkText(text, maxLength) {
    const chunks = [];
    
    if (text.length <= maxLength) {
      chunks.push(text);
      return chunks;
    }
    
    // 按句子分割
    const tokenizer = new natural.SentenceTokenizer();
    const sentences = tokenizer.tokenize(text);
    
    let currentChunk = '';
    
    for (const sentence of sentences) {
      // 如果添加这个句子会超出最大长度，先保存当前块
      if (currentChunk.length + sentence.length > maxLength) {
        chunks.push(currentChunk);
        currentChunk = sentence;
      } else {
        currentChunk += (currentChunk ? ' ' : '') + sentence;
      }
    }
    
    // 添加最后一个块
    if (currentChunk) {
      chunks.push(currentChunk);
    }
    
    return chunks;
  }

  /**
   * 提取文本中的关键词
   * @param {string} text - 文本
   * @returns {Array<string>} - 关键词数组
   */
  static extractKeywords(text) {
    // 使用TF-IDF提取关键词
    const tfidf = new natural.TfIdf();
    tfidf.addDocument(text);
    
    // 使用compromise提取名词和实体
    const doc = compromise(text);
    const nouns = doc.nouns().out('array');
    const entities = doc.topics().out('array');
    
    // 合并并去重
    const allTerms = [...new Set([...nouns, ...entities])];
    
    // 过滤掉太短的词
    const filteredTerms = allTerms.filter(term => term.length > 2);
    
    // 最多返回10个关键词
    return filteredTerms.slice(0, 10);
  }

  /**
   * 为内容生成标题
   * @param {string} content - 内容
   * @param {string} chapterTitle - 章节标题
   * @returns {string} - 生成的标题
   */
  static generateTitle(content, chapterTitle) {
    // 使用compromise提取主题
    const doc = compromise(content);
    const topics = doc.topics().out('array');
    
    // 如果找到主题，使用第一个主题作为标题基础
    if (topics.length > 0) {
      return `${chapterTitle} - ${topics[0]}`;
    }
    
    // 如果没有找到主题，使用内容的前几个词作为标题
    const words = content.split(' ').slice(0, 5).join(' ');
    return `${chapterTitle} - ${words}...`;
  }

  /**
   * 分析内容难度
   * @param {string} content - 内容
   * @returns {number} - 难度级别 (1-5)
   */
  static analyzeDifficulty(content) {
    // 使用多个因素来确定难度
    
    // 1. 句子长度
    const tokenizer = new natural.SentenceTokenizer();
    const sentences = tokenizer.tokenize(content);
    const avgSentenceLength = content.length / sentences.length;
    
    // 2. 词汇复杂度（使用平均词长作为简单指标）
    const words = content.split(/\s+/);
    const avgWordLength = words.reduce((sum, word) => sum + word.length, 0) / words.length;
    
    // 3. 技术术语比例（简单实现）
    const techTerms = ['algorithm', 'function', 'programming', 'database', 'variable', 'class', 'object', 'method', 'interface'];
    const techTermCount = words.filter(word => techTerms.some(term => word.toLowerCase().includes(term))).length;
    const techTermRatio = techTermCount / words.length;
    
    // 计算综合难度分数
    let difficultyScore = 1;
    
    if (avgSentenceLength > 20) difficultyScore += 1;
    if (avgSentenceLength > 30) difficultyScore += 1;
    
    if (avgWordLength > 6) difficultyScore += 1;
    if (avgWordLength > 8) difficultyScore += 1;
    
    if (techTermRatio > 0.05) difficultyScore += 1;
    
    // 确保难度在1-5范围内
    return Math.min(Math.max(difficultyScore, 1), 5);
  }

  /**
   * 构建卡片之间的关联关系
   * @param {Array} cards - 卡片数组
   * @returns {Promise<void>}
   */
  static async buildCardRelationships(cards) {
    // 为每张卡片找出相关卡片
    for (let i = 0; i < cards.length; i++) {
      const card = cards[i];
      const relatedCardsWithRelevance = [];
      
      // 简单实现：检查关键词重叠
      for (let j = 0; j < cards.length; j++) {
        if (i === j) continue; // 跳过自身
        
        const otherCard = cards[j];
        
        // 检查标签重叠
        const commonTags = card.tags.filter(tag => otherCard.tags.includes(tag));
        
        if (commonTags.length > 0) {
          relatedCardsWithRelevance.push({
            cardId: otherCard._id,
            relevance: commonTags.length / Math.max(card.tags.length, otherCard.tags.length)
          });
        }
      }
      
      // 按相关性排序，最多保留5个相关卡片
      relatedCardsWithRelevance.sort((a, b) => b.relevance - a.relevance);
      
      // 只保存相关卡片的ID，符合Card模型的定义
      card.relatedCards = relatedCardsWithRelevance.slice(0, 5).map(item => item.cardId);
      
      // 保存卡片
      try {
        await card.save();
      } catch (error) {
        console.error(`保存卡片关系时出错 (卡片ID: ${card._id}):`, error.message);
        // 如果保存失败，清空关系后重试
        card.relatedCards = [];
        await card.save();
      }
    }
  }

  /**
   * 将字符串类型的难度值转换为数字类型
   * @param {string|number} difficulty - 难度值，可以是字符串或数字
   * @returns {number} - 数字类型的难度值 (1-5)
   */
  static convertDifficultyToNumber(difficulty) {
    // 如果已经是数字，直接返回（确保在1-5范围内）
    if (typeof difficulty === 'number') {
      return Math.min(Math.max(difficulty, 1), 5);
    }
    
    // 如果是字符串，根据不同值转换
    if (typeof difficulty === 'string') {
      const difficultyMap = {
        'EASY': 1,
        'MEDIUM': 3,
        'HARD': 5,
        'LOW': 1,
        'MEDIUM_LOW': 2,
        'MEDIUM_HIGH': 4,
        'HIGH': 5
      };
      
      // 转换为大写并查找映射
      const upperDifficulty = difficulty.toUpperCase();
      if (difficultyMap[upperDifficulty] !== undefined) {
        return difficultyMap[upperDifficulty];
      }
      
      // 尝试直接解析为数字
      const parsedDifficulty = parseInt(difficulty, 10);
      if (!isNaN(parsedDifficulty)) {
        return Math.min(Math.max(parsedDifficulty, 1), 5);
      }
    }
    
    // 默认返回中等难度
    return 3;
  }

  /**
   * 更新文档的处理进度
   * @param {string} documentId - 文档ID
   * @param {Object} progress - 处理进度对象
   * @returns {Promise<void>}
   */
  static async updateProcessingProgress(documentId, progress) {
    try {
      const Document = require('../models/Document');
      
      // 添加时间戳
      progress.lastProcessedAt = new Date();
      
      // 更新文档的处理进度
      await Document.findByIdAndUpdate(documentId, {
        $set: {
          processingProgress: progress
        }
      });
      
      console.log(`[CardGenerator] 更新文档 ${documentId} 的处理进度: ${JSON.stringify(progress)}`);
    } catch (error) {
      console.error(`[CardGenerator] 更新处理进度时出错:`, error);
    }
  }
}

module.exports = CardGenerator; 